import { isArray, isObject } from '../core/helper'
const proxyHandler = function(){
  let that = this;
  return {
    set(target, key, value, receiver){
      if(isArray(value) || isObject(value)){
        value = proxy.call(that,value,this._handler)
      }
      that.publish(receiver, key, value)
      return Reflect.set(target, key, value, receiver);
    },
    get(target, key, receiver){
      return Reflect.get(target,key,receiver);
    }
  }
}
const proxyLoop = function(target,handler){
  for(let key in target){
    if(isArray(target[key]) || isObject(target[key])){
      proxyLoop(target[key])
      target[key] = new Proxy(target[key], handler)
    }
  }
  return target;
}
const proxy = function(data,_handler){
  let handler = _handler || proxyHandler.call(this);
  this._handler = handler;
  return new Proxy(proxyLoop(data,handler),handler)
}
class Observer {
  constructor(data){
    this.proxyData = proxy.call(this,data);
    this.subWeakMap = new WeakMap();
  }
  publish(target,key,value){
    if(value === target[key])return;
    let targetMap = this.subWeakMap.get(target) || {};
    (targetMap[key] || []).forEach(item=>{
      item && !item.isCancel && item(value);
    })
  }
  subscribe(target,key,handle){
    let targetMap = this.subWeakMap.get(target) || {}
    targetMap[key] = targetMap[key] || [];
    targetMap[key].push(handle);
    handle(target[key])
    this.subWeakMap.set(target,targetMap);
  }
}
export const reactive = function(model){
  let newObserver = new Observer(model);
  return newObserver
}